/*
 * Copyright 2011 Katsunori Koyanagi
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package sweezy.core.log
{
	import flash.utils.getQualifiedClassName;
	import sweezy.core.utils.now;

	public class Logger
	{

		private static var _emptyLogWriters:Vector.<ILogWriter> = new Vector.<ILogWriter>(0, true);

		private static var _internalCache:Object = {};

		private static var _logWriters:Vector.<ILogWriter> = new Vector.<ILogWriter>();

		private static var _loggers:Object = {};

		public static function addLogWriter(logWriter:ILogWriter):void
		{
			if (logWriter === null)
			{
				return;
			}

			_logWriters[_logWriters.length] = logWriter;
			_internalCache = null;
		}

		public static function getLogger(target:*):ILogger
		{
			var fqcn:String = null;

			if (target === null)
			{
				fqcn = "";
			}
			else if (target is String)
			{
				fqcn = target;
			}
			else
			{
				fqcn = getQualifiedClassName(target);
			}

			if (fqcn in _loggers)
			{
				return _loggers[fqcn];
			}

			var index:int = fqcn.lastIndexOf("::");
			var name:String;
			var category:String;

			if (index === -1)
			{
				name = fqcn;
				category = "";
			}
			else
			{
				name = fqcn.substring(index + 2);
				category = fqcn.substring(0, index);
			}

			var logger:LoggerImpl = new LoggerImpl(category, name);
			_loggers[fqcn] = logger;

			return logger;
		}

		public static function removeLogWriter(logWriter:ILogWriter):void
		{
			if (logWriter === null)
			{
				return;
			}

			for (var i:uint = 0, len:uint = _logWriters.length; i < len; i++)
			{
				if (_logWriters[i] === logWriter)
				{
					_logWriters.splice(i, 1);
					_internalCache = null;
					return;
				}
			}
		}

		internal static function clearInternalCache():void
		{
			_internalCache = null;
		}

		internal static function isEnabled(level:uint, category:String):Boolean
		{
			return getLogWriters(level, category).length > 0;
		}

		internal static function write(level:uint, logger:LoggerImpl, message:String, args:Array):void
		{
			var logWriters:Vector.<ILogWriter> = getLogWriters(level, logger._category);
			if (logWriters.length === 0)
			{
				return;
			}

			var time:Number = now();
			for each (var writer:ILogWriter in logWriters)
			{
				writer.write(time, logger._category, logger._name, level, message, args);
			}
		}

		private static function getLogWriters(level:uint, category:String):Vector.<ILogWriter>
		{
			var info:LogWritersInfo;
			var logWriter:ILogWriter;
			var index:uint = 0;

			if (_internalCache === null)
			{
				_internalCache = {};
			}
			if (!(category in _internalCache))
			{
				info = new LogWritersInfo();
				_internalCache[category] = info;
			}
			else
			{
				info = _internalCache[category];
			}

			switch (level)
			{
				case LogLevel.DEBUG:
					if (info.debug === null)
					{
						info.debug = new Vector.<ILogWriter>();
						for each (logWriter in _logWriters)
						{
							if (logWriter.accept(category, level))
							{
								info.debug[index++] = logWriter;
							}
							info.debug.fixed = true;
						}
					}

					return info.debug;

				case LogLevel.INFO:
					if (info.info === null)
					{
						info.info = new Vector.<ILogWriter>();
						for each (logWriter in _logWriters)
						{
							if (logWriter.accept(category, level))
							{
								info.info[index++] = logWriter;
							}
							info.info.fixed = true;
						}
					}

					return info.info;

				case LogLevel.WARN:
					if (info.warn === null)
					{
						info.warn = new Vector.<ILogWriter>();
						for each (logWriter in _logWriters)
						{
							if (logWriter.accept(category, level))
							{
								info.warn[index++] = logWriter;
							}
							info.warn.fixed = true;
						}
					}

					return info.warn;

				case LogLevel.ERROR:
					if (info.error === null)
					{
						info.error = new Vector.<ILogWriter>();
						for each (logWriter in _logWriters)
						{
							if (logWriter.accept(category, level))
							{
								info.error[index++] = logWriter;
							}
							info.error.fixed = true;
						}
					}

					return info.error;

				case LogLevel.FATAL:
					if (info.fatal === null)
					{
						info.fatal = new Vector.<ILogWriter>();
						for each (logWriter in _logWriters)
						{
							if (logWriter.accept(category, level))
							{
								info.fatal[index++] = logWriter;
							}
							info.fatal.fixed = true;
						}
					}

					return info.fatal;
			}

			return _emptyLogWriters;
		}
	}
}

import sweezy.core.log.ILogWriter;

class LogWritersInfo
{

	public var debug:Vector.<ILogWriter>;

	public var error:Vector.<ILogWriter>;

	public var fatal:Vector.<ILogWriter>;

	public var info:Vector.<ILogWriter>;

	public var warn:Vector.<ILogWriter>;
}
